package com.iot08.admin.service;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iot08.admin.enums.PayOrderTypeEnum;
import com.iot08.admin.service.page.PageVO;
import com.iot08.admin.service.page.PageableImpl;
import com.iot08.admin.utils.AlipayUtil;
import com.iot08.admin.utils.WxPayUtil;
import com.iot08.common.constant.RefundStatusEnum;
import com.iot08.common.entity.admin.RefundApply;
import com.iot08.common.entity.app.PayOrderInfo;
import com.iot08.common.response.Response;
import com.iot08.common.service.base.BaseAdminService;
import com.iot08.common.utils.DateUtil;
import com.iot08.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.ConvertOperators;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.addFields;

/**
 * @author cwj
 * @description
 * @date 2025/2/5 16:02
 **/
@Slf4j
@Service
public class RefundApplyService extends BaseAdminService<RefundApply> {

    @Resource
    private PayOrderInfoService payOrderInfoService;
    @Resource
    private WxPayUtil wxPayUtil;

    @Resource
    private AlipayUtil alipayUtil;

    public Page<RefundApply> list(PageVO page, String startTime, String endTime, String outTradeNo,String transactionId, String refundType,
                                  Integer orderType,Integer productType) {
        PageableImpl pageable = new PageableImpl();
        page.setSort(Sort.by(Sort.Order.desc("createTime")));
        pageable.setPage(page);

        Criteria criteria = new Criteria();
        if (StringUtil.isNotBlank(page.getSearchValue())) {
            criteria.and("_id").is(page.getSearchValue());
        }
        if (!StringUtils.isEmpty(outTradeNo)) {
            criteria.and("outTradeNo").is(outTradeNo);
        }
        if (!StringUtils.isEmpty(transactionId)) {
            criteria.and("transactionId").is(transactionId);
        }
        if(!ObjectUtils.isEmpty(orderType)) {
            criteria.and("orderType").is(orderType);
        }
        if(!ObjectUtils.isEmpty(productType)) {
            criteria.and("productType").is(productType);
        }
        try {
            if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true))
                        .lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            } else if(!StringUtils.isEmpty(startTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true));
            } else if(!StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            }
        } catch (Exception e) {
            log.error("查询支付订单出现异常，异常信息为：{}",e.getMessage());
        }
        if(!StringUtils.isEmpty(refundType)) {
            criteria.and("refundMethod").is(refundType);
        }

        Query query = new Query().addCriteria(criteria);
        long count = this.count(query);
        page.setTotalResult((int) count);
        List<RefundApply> list = this.find(query.with(pageable));
        return  new PageImpl<RefundApply>(list, pageable, count);
    }


    /**
     * @description 查询总退款金额
     * @author cwj
     * @param [id, startTime, endTime, outTradeNo, transactionId, refundType, orderType, productType]
     * @return java.lang.String
     * @date @time 2025/5/15 11:53
     **/
    public String queryRefundTotalByParam(String id,String startTime, String endTime, String outTradeNo,String transactionId,
                                          String refundType, Integer orderType,Integer productType){
        BigDecimal refundTotal = new BigDecimal(0);
        Criteria criteria = new Criteria();
        if (StringUtil.isNotBlank(id)) {
            criteria.and("_id").is(id);
        }
        if (!StringUtils.isEmpty(outTradeNo)) {
            criteria.and("outTradeNo").is(outTradeNo);
        }
        if (!StringUtils.isEmpty(transactionId)) {
            criteria.and("transactionId").is(transactionId);
        }
        if(!ObjectUtils.isEmpty(orderType)) {
            criteria.and("orderType").is(orderType);
        }
        if(!ObjectUtils.isEmpty(productType)) {
            criteria.and("productType").is(productType);
        }
        try {
            if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true))
                        .lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            } else if(!StringUtils.isEmpty(startTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true));
            } else if(!StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            }
        } catch (Exception e) {
            log.error("查询支付订单出现异常，异常信息为：{}",e.getMessage());
        }
        if(!StringUtils.isEmpty(refundType)) {
            criteria.and("refundMethod").is(refundType);
        }
        criteria.and("status").is("SUCCESS");
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                addFields().addField("refundAmountDecimal")
                        .withValue(ConvertOperators.ToDecimal.toDecimal("$refund"))
                        .build(),
                Aggregation.group()
                        .sum("refundAmountDecimal").as("refundTotal")
        );
        AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "refund_apply_order", Document.class);
        Document result = results.getUniqueMappedResult();
        if(org.apache.commons.lang3.ObjectUtils.isNotEmpty(result) && org.apache.commons.lang3.ObjectUtils.isNotEmpty(result.get("refundTotal"))) {
            refundTotal = new BigDecimal(result.get("refundTotal").toString());
        }
        return refundTotal.toString();
    }

    /**
     * @description 查询是否存在已经退款或正在退款中的退款申请
     * @author cwj
     * @param [orderId]
     * @return boolean
     * @date @time 2025/2/10 11:31
     **/
    public boolean queryrRefundApplyExists(String orderId){
        Query query = new Query(Criteria.where("outTradeNo").is(orderId).and("status").in("SUCCESS","PROCESSING")).limit(1);
        RefundApply refundApply = this.findOne(query);
        return !ObjectUtils.isEmpty(refundApply);
    }

    /**
     * @description 保存
     * @author cwj
     * @param [jsonObject, methodType]
     * @return void
     * @date @time 2025/2/6 10:20
     **/
    public RefundApply saveRefundApplyByJson(JSONObject jsonObject,String methodType){
        //保存退款申请记录
        RefundApply refundApply = assembleRefundApply(jsonObject, methodType);
        return this.save(refundApply);
    }

    /**
     * @description 保存退款申请记录
     * @author cwj
     * @param [transactionId, orderId]
     * @return com.iot08.common.entity.admin.RefundApply
     * @date @time 2025/2/6 10:38
     **/
    public RefundApply saveRefundApplyByOrderId(String transactionId,String orderId,String methodType,Integer orderType, Integer productType ,String refundReason,BigDecimal total){
        RefundApply refundApply = new RefundApply();
        refundApply.setTransactionId(transactionId);
        refundApply.setOutTradeNo(orderId);
        refundApply.setRefundMethod(methodType);
        refundApply.setOrderType(orderType);
        refundApply.setProductType(productType);
        refundApply.setRefundReason(refundReason);
        //退款时，设置退款状态为退款中
        refundApply.setStatus("PROCESSING");
        //订单总金额
        refundApply.setTotal(total);
        refundApply.setCreateTime(new Date());
        refundApply.setUpdateTime(new Date());
        refundApply.setCreateTimestamp(new Date().getTime());
        return this.save(refundApply);
    }

    /**
     * @description 更新微信退款申请订单
     * @author cwj
     * @param [jsonObject, methodType]
     * @return com.iot08.common.entity.admin.RefundApply
     * @date @time 2025/2/6 10:42
     **/
    public void updateRefundApplyByJson(JSONObject jsonObject){
        //保存退款申请记录
        Update update = assembleRefundApplyUpdate(jsonObject);
        this.updateById(new ObjectId(jsonObject.getString("out_refund_no")),update);
    }
    
    /**
     * @description 更新退款申请信息的状态信息
     * @author cwj-
     * @param [refundId, status]
     * @return void
     * @date @time 2025/2/10 17:23
     **/
    public void updateRefundApplyStatusById(String refundId,String status) {
        //更新退款状态
        Update update = new Update();
        update.set("status", status);
        this.updateById(new ObjectId(refundId), update);
    }

    /**
     * @description 更新支付宝退款申请订单
     * @author cwj
     * @param [response]
     * @return void
     * @date @time 2025/2/7 9:43
     **/
    public void updateRefundApplyByAlipayTradeRefund(AlipayTradeRefundResponse response,String outRequestNo){
        Update update = new Update();
        update.set("buyerLogonId",response.getBuyerLogonId());
        update.set("status","PROCESSING");
        update.set("fundChange",response.getFundChange());
        update.set("fundsAccount",response.getStoreName());
        update.set("refund",response.getRefundFee());
        if(!StringUtils.isEmpty(response.getSendBackFee())) {
            //商户实际退款金额
            update.set("sellerRealRefund",new BigDecimal(response.getSendBackFee()));
        }
        if(!StringUtils.isEmpty(response.getBuyerUserId())){
            update.set("buyerUserId",response.getBuyerUserId());
        }
        if(!StringUtils.isEmpty(response.getBuyerOpenId())){
            update.set("buyerOpenId",response.getBuyerOpenId());
        }
        update.set("updateTime",new Date());
        this.updateById(new ObjectId(outRequestNo),update);
    }

    /**
     * @description 构建RefundApply对象
     * @author cwj
     * @param [jsonObject, methodType]
     * @return com.iot08.common.entity.admin.RefundApply
     * @date @time 2025/2/6 10:20
     **/
    private RefundApply assembleRefundApply(JSONObject jsonObject, String methodType) {
        RefundApply refundApply = new RefundApply();
        refundApply.setId(jsonObject.getString("out_refund_no"));
        refundApply.setRefundNo(jsonObject.getString("refund_id"));
        refundApply.setRefundMethod(methodType);
        refundApply.setTransactionId(jsonObject.getString("transaction_id"));
        refundApply.setOutTradeNo(jsonObject.getString("out_trade_no"));
        refundApply.setChannel(jsonObject.getString("channel"));
        refundApply.setUserReceivedAccount(jsonObject.getString("user_received_account"));
        if(!StringUtils.isEmpty(jsonObject.getString("success_time"))) {
            refundApply.setSuccessTime(DateUtil.rfc3339FormatDateStr(jsonObject.getString("success_time"),DateUtil.FORMAT_1));
        }
        refundApply.setRefundCreateTime(DateUtil.rfc3339FormatDateStr(jsonObject.getString("create_time"),DateUtil.FORMAT_1));
        refundApply.setStatus(jsonObject.getString("status"));
        refundApply.setFundsAccount(jsonObject.getString("funds_account"));
        JSONObject amount = jsonObject.getJSONObject("amount");
        //将分转成元
        refundApply.setTotal(amount.getBigDecimal("total").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setRefund(amount.getBigDecimal("refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setPayerTotal(amount.getBigDecimal("payer_total").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setPayerRefund(amount.getBigDecimal("payer_refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setSettlementRefund(amount.getBigDecimal("settlement_refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setSettlementTotal(amount.getBigDecimal("settlement_total").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setDiscountRefund(amount.getBigDecimal("discount_refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        refundApply.setCurrency(amount.getString("currency"));
        if(!ObjectUtils.isEmpty(amount.get("refund_fee"))){
            refundApply.setRefundFee(amount.getBigDecimal("refund_fee").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        }
        refundApply.setCreateTime(new Date());
        refundApply.setUpdateTime(new Date());
        refundApply.setCreateTimestamp(new Date().getTime());
        return refundApply;
    }

    /**
     * @description 构建更新RefundApply的对象
     * @author cwj
     * @param [jsonObject]
     * @return org.springframework.data.mongodb.core.query.Update
     * @date @time 2025/2/6 11:27
     **/
    private Update assembleRefundApplyUpdate(JSONObject jsonObject) {
        Update update = new Update();
        update.set("refundNo",jsonObject.getString("refund_id"));
        update.set("channel",jsonObject.getString("channel"));
        update.set("userReceivedAccount",jsonObject.getString("user_received_account"));
        if(!StringUtils.isEmpty(jsonObject.getString("success_time"))) {
            update.set("successTime", DateUtil.rfc3339FormatDateStr(jsonObject.getString("success_time"), DateUtil.FORMAT_1));
        }
        update.set("refundCreateTime",DateUtil.rfc3339FormatDateStr(jsonObject.getString("create_time"),DateUtil.FORMAT_1));
        update.set("status",jsonObject.getString("status"));
        update.set("fundsAccount",jsonObject.getString("funds_account"));
        JSONObject amount = jsonObject.getJSONObject("amount");
        //将分转成元
        update.set("total",amount.getBigDecimal("total").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("refund",amount.getBigDecimal("refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("payerTotal",amount.getBigDecimal("payer_total").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("payerRefund",amount.getBigDecimal("payer_refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("settlementRefund",amount.getBigDecimal("settlement_refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("settlementTotal",amount.getBigDecimal("settlement_total").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("discountRefund",amount.getBigDecimal("discount_refund").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        update.set("currency",amount.getString("currency"));
        if(!ObjectUtils.isEmpty(amount.get("refund_fee"))){
            update.set("refundFee",amount.getBigDecimal("refund_fee").divide(new BigDecimal(100), 2, RoundingMode.DOWN));
        }
        update.set("updateTime",new Date());
        return update;
    }


    /**
     * @description 退款状态信息查询
     * @author cwj
     * @param [refundId]
     * @return com.iot08.common.response.Response<java.lang.Object>
     * @date @time 2025/2/10 14:28
     **/
    public Response<Object> queryRefundStatueInfo(String refundId) {
        //查询退款申请
        RefundApply refundApply = this.findById(new ObjectId(refundId));
        if(RefundStatusEnum.SUCCESS.getKey().equals(refundApply.getStatus())){
            return Response.failedResponse("退款申请已经被成功处理");
        } else if(RefundStatusEnum.CLOSED.getKey().equals(refundApply.getStatus())){
            return Response.failedResponse("退款申请处理失败，请去支付订单页面重新申请退款");
        } else if (RefundStatusEnum.ABNORMAL.getKey().equals(refundApply.getStatus())) {
            return Response.failedResponse("退款申请处理出现异常，请去支付订单页面重新申请退款");
        } else {
            if("wechatRefund".equals(refundApply.getRefundMethod())) {
                try {
                    //查询退款状态信息
                    String responseBody = wxPayUtil.queryRefundStatueInfo(refundId);
                    if (StringUtils.isEmpty(responseBody)) {
                        log.error("查询退款订单查询失败");
                        return Response.failedResponse("退款订单状态查询失败");
                    }
                    ObjectMapper objectMapper = new ObjectMapper();
                    JSONObject responseJson = objectMapper.readValue(responseBody, JSONObject.class);
                    String refundStatus = responseJson.getString("status");
                    //更新退款状态
                    updateRefundApplyStatusById(refundId,refundStatus);
                    if (RefundStatusEnum.SUCCESS.getKey().equals(refundStatus)) {
                        //更新支付订单的状态
                        payOrderInfoService.updatePayOrderRefundStatus(refundApply.getOutTradeNo(),3,3);
                    }
                } catch (Exception e) {
                    log.error("查询退款申请出现异常，出现异常的退款订单为：{}", refundId);
                    return Response.failedResponse("退款订单状态查询失败");
                }
            } else if ("alipayRefund".equals(refundApply.getRefundMethod())) {
                try {
                    AlipayTradeFastpayRefundQueryResponse response = alipayUtil.queryRefundInfo(refundId,refundApply.getTransactionId(),refundApply.getOutTradeNo());
                    if(response.isSuccess()){
                        if("REFUND_SUCCESS".equals(response.getRefundStatus())){
                            //更新退款申请的状态信息
                            updateRefundApplyStatusById(refundId,RefundStatusEnum.SUCCESS.getKey());
                            //更新支付订单的状态
                            payOrderInfoService.updatePayOrderRefundStatus(refundApply.getOutTradeNo(),3,3);
                        } else if("REFUND_FAIL".equals(response.getRefundStatus()) || "REFUND_CLOSED".equals(response.getRefundStatus())){
                            updateRefundApplyStatusById(refundId,RefundStatusEnum.CLOSED.getKey());
                        } else if("WAIT_REFUND".equals(response.getRefundStatus())) {
                            updateRefundApplyStatusById(refundId,RefundStatusEnum.PROCESSING.getKey());
                        }
                    } else {
                        return Response.failedResponse("退款订单状态查询失败");
                    }
                }catch (AlipayApiException ae){
                    log.error("查询退款信息出现异常，异常信息为：{}",ae.getMessage());
                    return Response.failedResponse("退款订单状态查询失败");
                }
            } else if("appleRefund".equals(refundApply.getRefundMethod())){

            } else {
                log.error("退款订单类型不存在");
                return Response.failedResponse("退款订单的类型错误，无法退款，请联系管理员");
            }
        }
        return Response.successResponse("退款订单查询成功");
    }
    
    /**
     * @description 导出退款订单数据
     * @author cwj
     * @param [refundId, startTime, endTime, transactionId, outTradeNo, refundType, response]
     * @return void
     * @date @time 2025/4/20 18:13
     **/
    public void importData(String refundId,String startTime,String endTime,String transactionId,String outTradeNo, 
                           String refundType,Integer orderType,Integer productType, HttpServletResponse response) {
        try {
            Criteria criteria = new Criteria();
            if (StringUtil.isNotBlank(refundId)) {
                criteria.and("_id").is(refundId);
            }
            if (!StringUtils.isEmpty(outTradeNo)) {
                criteria.and("outTradeNo").is(outTradeNo);
            }
            if (!StringUtils.isEmpty(transactionId)) {
                criteria.and("transactionId").is(transactionId);
            }
            if(!ObjectUtils.isEmpty(orderType)) {
                criteria.and("orderType").is(orderType);
            }
            if(!ObjectUtils.isEmpty(productType)) {
                criteria.and("productType").is(productType);
            }
            try {
                if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                    criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true))
                            .lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
                } else if(!StringUtils.isEmpty(startTime)) {
                    criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true));
                } else if(!StringUtils.isEmpty(endTime)) {
                    criteria.and("createTimestamp").lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
                }
               /* if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                    criteria.and("createTime").gte(DateUtil.convertStrToDate(startTime,DateUtil.FORMAT_4,true))
                            .lte(DateUtil.convertStrToDate(endTime,DateUtil.FORMAT_4,false));
                } else if(!StringUtils.isEmpty(startTime)) {
                    criteria.and("createTime").gte(DateUtil.convertStrToDate(startTime,DateUtil.FORMAT_4,true));
                } else if(!StringUtils.isEmpty(endTime)) {
                    criteria.and("createTime").lte(DateUtil.convertStrToDate(endTime,DateUtil.FORMAT_4,false));
                }*/
            } catch (Exception e) {
                log.error("查询支付订单出现异常，异常信息为：{}",e.getMessage());
            }
            if(!StringUtils.isEmpty(refundType)) {
                criteria.and("refundMethod").is(refundType);
            }

            Query query = new Query().addCriteria(criteria);
            List<RefundApply> list = this.find(query.with(Sort.by(Sort.Order.desc("createTime"))));
            //导出查询到的数据
            exportLargeData(list,response);
        } catch (Exception e) {
            log.error("导出退款订单出现异常，异常信息为：{}",e.getMessage());
        }
    }

    /**
     * @description 导出查询数据
     * @author cwj
     * @param [payOrderInfos, response]
     * @return void
     * @date @time 2025/4/20 18:15
     **/
    public void exportLargeData(List<RefundApply> refundApplies, HttpServletResponse response) throws Exception {
        // 创建流式工作簿，窗口大小为100（表示只保留100行在内存）
        SXSSFWorkbook workbook = new SXSSFWorkbook(100);
        Sheet sheet = workbook.createSheet("退款订单");
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("退款单号");
        headerRow.createCell(1).setCellValue("订单号");
        headerRow.createCell(2).setCellValue("支付订单号");
        headerRow.createCell(3).setCellValue("购买类型");
        headerRow.createCell(4).setCellValue("退款状态");
        headerRow.createCell(5).setCellValue("退款方式");
        headerRow.createCell(6).setCellValue("退款金额");
        headerRow.createCell(7).setCellValue("订单总金额");
        headerRow.createCell(8).setCellValue("币种");
        headerRow.createCell(9).setCellValue("退款原因");
        headerRow.createCell(10).setCellValue("创建时间");
        for (int i = 0; i < refundApplies.size(); i++) {
            RefundApply refundApply = refundApplies.get(i);
            Row row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(refundApply.getId());
            row.createCell(1).setCellValue(refundApply.getOutTradeNo());
            row.createCell(2).setCellValue(refundApply.getTransactionId());
            row.createCell(3).setCellValue(ObjectUtils.isEmpty(refundApply.getOrderType())?"会员": PayOrderTypeEnum.getKeyByValue(refundApply.getOrderType()));
            row.createCell(4).setCellValue(refundApply.getStatus());
            row.createCell(5).setCellValue(refundApply.getRefundMethod());
            row.createCell(6).setCellValue(ObjectUtils.isEmpty(refundApply.getRefund()) ? "":refundApply.getRefund().toString());
            row.createCell(7).setCellValue(ObjectUtils.isEmpty(refundApply.getTotal()) ? "":refundApply.getTotal().toString());
            row.createCell(8).setCellValue(StringUtils.isEmpty(refundApply.getCurrency())?"":refundApply.getCurrency());
            row.createCell(9).setCellValue(refundApply.getRefundReason());
            row.createCell(10).setCellValue(ObjectUtils.isEmpty(refundApply.getCreateTime())?"":DateUtil.dateToStr(refundApply.getCreateTime(),DateUtil.FORMAT_1));
        }
        // 设置导出
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=" +
                URLEncoder.encode("退款订单.xlsx", "UTF-8"));
        workbook.write(response.getOutputStream());
        // 清理临时文件
        workbook.dispose();
        workbook.close();
    }


    /**
     * @description 更新退款订单的订单类型及产品类型信息
     * @author cwj
     * @param []
     * @return com.iot08.common.response.Response<java.lang.Object>
     * @date @time 2025/5/1 10:03
     **/
    public Response<Object> updateRefundApplyOrderType(){
        Query query = new Query( new Criteria().orOperator(
                Criteria.where("orderType").is(null),
                Criteria.where("productType").is(null)
        ));
        List<RefundApply> refundApplies = this.find(query);
        if(!CollectionUtils.isEmpty(refundApplies)) {
            List<String> orderIds = refundApplies.stream().map(RefundApply::getOutTradeNo).collect(Collectors.toList());
            List<PayOrderInfo> payOrderInfos = payOrderInfoService.queryPayOrderInfoByIds(orderIds);
            if(!CollectionUtils.isEmpty(payOrderInfos)) {
                refundApplies.forEach(ra->{
                    payOrderInfos.forEach(p->{
                        if(ra.getOutTradeNo().equals(p.getId())) {
                            Update update = new Update();
                            update.set("orderType",p.getOrderType());
                            update.set("productType",p.getProductType());
                            this.updateById(new ObjectId(ra.getId()),update);
                        }
                    });
                });
            }
        }
        return Response.successResponse();
    }

    /**
     * @description 查询退款总金额
     * @author cwj
     * @param []
     * @return com.iot08.common.response.Response<java.lang.Object>
     * @date @time 2025/5/14 11:42
     **/
    public Response<Object> queryRefundTotal(){
        Criteria criteria = new Criteria();
        BigDecimal refundTotal = new BigDecimal(0);
        criteria.and("status").is("SUCCESS");
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                addFields().addField("refundAmountDecimal")
                        .withValue(ConvertOperators.ToDecimal.toDecimal("$refund"))
                        .build(),
                Aggregation.group()
                        .sum("refundAmountDecimal").as("refundTotal")
        );
        AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "refund_apply_order", Document.class);
        Document result = results.getUniqueMappedResult();
        if(org.apache.commons.lang3.ObjectUtils.isNotEmpty(result) && org.apache.commons.lang3.ObjectUtils.isNotEmpty(result.get("refundTotal"))) {
            refundTotal = new BigDecimal(result.get("refundTotal").toString());
        }
        Response res = Response.successResponse();
        res.setData(refundTotal);
        return res;
    }

}
